<template>
  <div
    v-bkloading="{ isLoading }"
    class="job-file-system">
    <template v-if="model == 'folder'">
      <div class="file-system-top ">
        <bk-input
          v-model="filter"
          class="filter-inp"
          placeholder="请输入文件名/文件夹名"
          right-icon="bk-icon icon-search"
          @change="search">
          <template slot="prepend">
            <div class="group-text">
              搜索
            </div>
          </template>
        </bk-input>
        <bk-button
          v-if="!!pathNode.length"
          class="back-btn"
          theme="primary"
          @click="handlerback">
          返回上一层
        </bk-button>
      </div>
      <div
        v-if="!!pathNode.length"
        class="file-cur-path">
        <span>当前路径:</span>
        <bk-tag theme="info">
          /{{ pathNode.join("/") }}/
        </bk-tag>
      </div>
      <bk-big-tree
        ref="tree"
        class="topology-tree scrollbar"
        :data="fileList"
        :default-expanded-nodes="[]"
        enable-title-tip
        :options="{ idKey: 'id' }">
        <div
          slot-scope="{ node, data }"
          class="node-info clearfix"
          :class="[{ 'is-file': !data.folder }]">
          <div
            class="node-left-infor"
            @click=" handlerNode(data)">
            <bk-icon
              v-if="data.folder"
              type="folder-open-shape" />
            <i
              v-else
              class="node-icon bk-icon icon-text-file" />
            <span
              class="node-name"
              :title="data.name">{{ data.name }}</span>
          </div>
          <div class="node-right-infor">
            <span class="node-infor"> {{ data.createTime }}</span>
            <span class="node-infor size"> {{ formatFileSize(data.size) }}</span>
          </div>
          <div
            v-if="!data.folder"
            class="node-right-infor-action">
            <bk-icon
              v-if="isView(data) || isImages(data)"
              title="查看"
              type="eye"
              @click="handlerView(data)" />
            <bk-icon
              title="下载"
              type="download"
              @click="handlerDowmload(data)" />
          </div>
        </div>
      </bk-big-tree>
      <div
        v-if="fileList.length === 0"
        class="job-empty">
        <template>
          <img
            src="/static/images/search-empty.svg"
            :style="{ width: `120px` }">
          <div class="job-empty-text">
            <slot>无内容</slot>
          </div>
        </template>
      </div>
    </template>
    <template v-if="model == 'view'">
      <div class="file-content">
        <div class="mb10">
          <span class="mr5 f14">开启实时输出：</span>
          <bk-switcher
            v-model="isLine"
            :disabled="isError"
            off-text="关闭"
            on-text="开启"
            show-text
            size="small"
            theme="primary" />
        </div>
        <div
          v-if="!isError"
          class="content-inner scrollbar">
          <pre>{{ content }}</pre>
        </div>
        <div
          v-else
          class="job-empty">
          <template>
            <img
              src="/static/images/search-empty.svg"
              :style="{ width: `120px` }">
            <div class="job-empty-text">
              <slot>内容加载失败！</slot>
            </div>
          </template>
        </div>
      </div>
    </template>

    <jb-dialog
      v-model="isShowFileRelate"
      header-position="left"
      ok-text="确定"
      title="文件管理"
      :width="drectoryScrollParams.model == 'view' ? 880 : 780">
      <div class="drectory-scroll-inner">
        <template v-if="drectoryScrollParams.model == 'view'">
          <drectory-scroll
            v-if="isShowFileRelate"
            :params="drectoryScrollParams" />
        </template>
        <bk-zoom-image
          v-if="drectoryScrollParams.model == 'image'"
          v-bkloading="{ isLoading: isLoadingImage }"
          class="zoom-image"
          :src="drectoryScrollParams.path" />
      </div>
    </jb-dialog>
  </div>
</template>
<script>
  import {
    messageError,
    messageSuccess,
  } from '@/common/bkmagic';
  import DrectoryScroll from '@/components/drectory-scroll';
  import { DIRSCROLL } from '@/domain/service/slurm';
  export default {
    name: 'DrectoryScroll',
    components: {
      DrectoryScroll,
    },
    props: ['params'],
    data() {
      return {
        XApiKey: 'bridgekube',
        filter: '',
        isLoading: true,
        fileList: [],
        pathNode: [],
        isLine: false,
        content: null,
        timer: null,
        isError: false,
        isLoadingImage: false,
        isShowFileRelate: false,
        drectoryScrollParams: {
          model: 'view',
          path: '',
        },
      };
    },
    computed: {
      model() {
        return this.params.model;
      },
    },
    watch: {
      isLine() {
        if (this.isLine) {
          this.initTimer();
        } else {
          this.clearTimer();
        }
      },
      params: {
        handler() {
          this.isLine = false;
          this.pathNode = [];
          this.isLoading = true;
          this.fetchPath();
        },
        deep: true,
      },
    },
    created() {
      this.isLoading = true;
      this.fetchPath();
    },
    beforeDestroy() {
      this.isLine = false;
      this.pathNode = [];
    },
    methods: {
      async fetchPath(callback) {
        try {
          if (this.model == 'view') {
            const path = `${this.params.path}`;
            const response = await fetch(`${DIRSCROLL}/list_directory/read_file?path=${path}`, {
              headers: {
                'X-Api-Key': this.XApiKey,
              },
            });
            const data = await response.text();
            const { data: d } = JSON.parse(data);

            this.content = d.content;
            this.isLoading = false;

            this.timer = setTimeout(() => {
              callback && callback(this.isLine ? callback : () => { });
            }, 1000);
          } else if (this.model == 'folder') {
            const path = `${this.params.path}${this.pathNode.join('/')}/`?.replace(/^(.*)\/logs\/$/, '$1/');
            const response = await fetch(`${DIRSCROLL}/list_directory/list?path=${path}`, {
              headers: {
                'X-Api-Key': this.XApiKey,
              },
            });
            const data = await response.text();
            const { data: d } = JSON.parse(data);

            this.fileList = (d.children || []).map(item => ({ ...item, folder: item.type !== 'file' }));
            this.isLoading = false;
          }
        } catch (error) {
          this.isLoading = false;
          this.isError = true;
          messageError('文件下载失败，请重试！');
        }
      },
      handlerNode({ name, folder }) {
        if (folder) {
          this.pathNode.push(name);
          this.fetchPath();
        }
      },
      handlerView({ name }) {
        const path = `${this.params.path}${this.pathNode.join('/')}/${name}`;
        if (!this.isImages({ name })) {
          this.drectoryScrollParams = {
            model: 'view',
            path,
          };
          this.isShowFileRelate = true;
        } else {
          this.isLoadingImage = true;
          this.handlerDowmload({ name }, (path) => {
            this.drectoryScrollParams = {
              model: 'image',
              path,
            };
            this.isShowFileRelate = true;
            this.isLoadingImage = false;
          });
        }
      },
      async handlerDowmload({ name }, callback) {
        const path = `${this.params.path}${this.pathNode.join('/')}/${name}`.replace("logs/","");
        const response = await fetch(`${DIRSCROLL}/list_directory/download_file?path=${path}`, {
          headers: {
            'X-Api-Key': this.XApiKey,
          },
        }).then((response) => {
          if (!response.ok) {
            messageError('文件下载失败，请重试！');
            throw new Error('File download failed');
          }
          return response.blob();
        })
          .then((blob) => {
            const url = window.URL.createObjectURL(blob);
            if (callback) {
              callback(url);
            } else {
              const link = document.createElement('a');
              link.href = url;
              link.download = path.split('/').pop();
              link.click();

              // 释放 URL 对象
              window.URL.revokeObjectURL(url);

              messageSuccess('文件下载成功！');
            }
          })
          .catch((error) => {
            messageError('文件下载失败，请重试！');
            this.isLoadingImage = false;
          });
      },
      handlerback() {
        this.pathNode.pop();
        this.fetchPath();
      },
      search() {
        this.$refs.tree.filter(this.filter);
      },
      isView({ name }) {
        const path = `${this.params.path}${this.pathNode.join('/')}/${name}`;
        const [_, suffix] = path.split('/').pop()
          .split('.');
        if (!suffix) return true;
        return ['txt', 'log', 'logs', 'py', 'sh'].indexOf(suffix.toLowerCase()) != -1;
      },
      isImages({ name }) {
        const path = `${this.params.path}${this.pathNode.join('/')}/${name}`;
        const [_, suffix] = path.split('/').pop()
          .split('.');
        if (!suffix) return false;
        return ['jpg', 'png', 'gif', 'webp', 'svg', 'bmp', 'tiff', 'heif', 'jp2', 'ico', 'avif'].indexOf(suffix.toLowerCase()) != -1;
      },
      formatFileSize(bytes) {
        if (bytes === 0 || !bytes) return '-';

        const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
        const size = Math.floor(Math.log(bytes) / Math.log(1024));
        const formattedSize = (bytes / Math.pow(1024, size)).toFixed(2);

        return `${formattedSize} ${units[size]}`;
      },
      initTimer() {
        this.fetchPath(this.fetchPath);
      },
      clearTimer() {
        this.timer && clearInterval(this.timer);
      },
    },
  };
</script>
<style lang='postcss' scoped>
.job-file-system {
    height: 450px;
}

.file-system-top {
    display: flex;
    justify-content: space-between;

    .filter-inp {
        width: calc(100% - 140px);
    }

    .back-btn {}

}

.file-cur-path {
    margin-top: 10px;
    font-size: 12px;

    span {
        display: inline-block;
        margin-right: 5px;
    }
}

.topology-tree {
    height: calc(100% - 52px) !important;
    padding: 10px 0;
    margin-right: 2px;

    .node-info {
        display: flex;
        justify-content: space-between;

        .node-right-infor {
            .node-infor {
                display: inline-block;
                font-size: 12px;
                margin: 0 10px;

                &.size {
                    text-align: right;
                    min-width: 110px;
                }
            }
        }

        .node-icon {
            margin: 8px 4px 8px 0;
            line-height: 1.666667;
            text-align: center;
            font-size: 18px;
            font-style: normal;

            &.is-template {
                background-color: #97aed6;
            }

            &.is-selected {
                background-color: var(--text-color-brand);
            }

            .icon-cc-business-set {
                vertical-align: 0;
                font-size: 16px;
            }
        }

        .node-right-infor-action {
            display: none;

            i {
                color: var(--color-primary);
                margin: 0 5px;
            }
        }

        &.is-file {
            &:hover {
                .node-right-infor {
                    display: none;
                }

                .node-right-infor-action {
                    display: block;
                }
            }
        }

        &:hover {

            .node-icon {
                color: var(--color-primary);
            }

            .node-name {
                color: var(--color-primary);
            }
        }
    }
}

.file-content {
    height: 100%;
    overflow: hidden;

    .content-inner {
        background: #202024;
        color: #fff;
        font-size: 14px;
        border-radius: 2px;
        padding: 5px 10px;
        height: calc(100% - 38px);

        pre {
            white-space: pre-wrap;
            word-wrap: break-word;
            font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
        }
    }
}

.job-empty {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    font-size: 12px;
    line-height: 1;
    color: #979ba5;
    text-align: center;
    flex-direction: column;
    align-items: center;
    justify-content: center;

    .job-empty-text {
        margin-top: 20px;

        * {
            font-size: 12px !important;
        }
    }
}

.scrollbar {
    overflow-y: auto;
    overflow-x: hidden;

    &::-webkit-scrollbar {
        width: 6px;
    }

    &::-webkit-scrollbar-thumb {
        background-color: #dcdee5;
        border-radius: 3px;
    }

}
</style>
